/**
 * User Authentication Manager
 * Manages user authentication based on .userlist file
 */

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

class UserAuthManager {
  constructor() {
    this.userListPath = path.join(path.dirname(__dirname), '.userlist');
    this.users = [];
    this.enabled = false;
    this.loadUsers();
  }

  /**
   * Load users from .userlist file
   */
  loadUsers() {
    try {
      if (fs.existsSync(this.userListPath)) {
        const fileContent = fs.readFileSync(this.userListPath, 'utf8');
        const data = JSON.parse(fileContent);
        
        if (Array.isArray(data) && data.length > 0) {
          this.users = data;
          this.enabled = true;
          console.log(`✅ User authentication enabled with ${this.users.length} users`);
          this.users.forEach((user, index) => {
            console.log(`  User ${index + 1}: ${user.name}`);
          });
        } else {
          console.log('⚠️  .userlist file is empty, authentication disabled');
          this.enabled = false;
        }
      } else {
        console.log('ℹ️  No .userlist file found, authentication disabled');
        this.enabled = false;
      }
    } catch (error) {
      console.error('❌ Error loading .userlist file:', error.message);
      this.enabled = false;
    }
  }

  /**
   * Reload users from file (hot reload)
   */
  reload() {
    this.loadUsers();
  }

  /**
   * Check if authentication is enabled
   */
  isEnabled() {
    return this.enabled;
  }

  /**
   * Validate user token
   * @param {string} token - The token to validate
   * @returns {Object|null} Returns user object if valid, null otherwise
   */
  validateToken(token) {
    if (!this.enabled || !token) {
      console.log(`❌ Token validation failed: enabled=${this.enabled}, token=${token ? 'present' : 'missing'}`);
      return null;
    }
  
    // Trim whitespace and normalize token
    const cleanToken = token.trim();
    console.log(`🔍 Validating token: ${cleanToken.substring(0, 10)}...`);
    console.log(`🔍 Token type detected: ${cleanToken.startsWith('sk-ant-') ? 'Anthropic API Token' : cleanToken.startsWith('oauth-') ? 'OAuth Token' : 'Custom User Token'}`);
    console.log(`🔍 Token length: ${cleanToken.length}`);
    console.log(`🔍 Available tokens: ${this.users.length}`);
    
    // Debug: Show stored token info (masked)
    this.users.forEach((user, index) => {
      const storedToken = user.token.trim();
      console.log(`🔍 Stored token ${index + 1} (${user.name}): ${storedToken.substring(0, 10)}... (length: ${storedToken.length})`);
    });
    
    // Check for exact match with the stored token
    const user = this.users.find(u => {
      const storedToken = u.token.trim();
      const match = storedToken === cleanToken;
      console.log(`🔍 Comparing with user ${u.name}:`);
      console.log(`   Input token: ${cleanToken.substring(0, 10)}... (length: ${cleanToken.length})`);
      console.log(`   Stored token: ${storedToken.substring(0, 10)}... (length: ${storedToken.length})`);
      console.log(`   Result: ${match ? '✅ MATCH' : '❌ NO MATCH'}`);
      return match;
    });
    
    if (user) {
      console.log(`✅ Token validated for user: ${user.name}`);
    } else {
      console.log(`❌ No matching user found for token`);
      console.log(`❌ This might be an OAuth token trying to authenticate against user token system`);
    }
    
    return user || null;
  }

  /**
   * Extract token from request
   * @param {Object} req - Express request object
   * @returns {string|null} The extracted token
   */
  extractToken(req) {
    console.log(`🔍 Extracting token from ${req.method} ${req.path}`);
    
    // Debug: Log all relevant headers
    console.log('🔍 Request headers for token extraction:');
    console.log(`   authorization: ${req.headers['authorization'] ? req.headers['authorization'].substring(0, 20) + '...' : 'not present'}`);
    console.log(`   x-api-key: ${req.headers['x-api-key'] ? req.headers['x-api-key'].substring(0, 10) + '...' : 'not present'}`);
    console.log(`   x-user-token: ${req.headers['x-user-token'] ? req.headers['x-user-token'].substring(0, 10) + '...' : 'not present'}`);
    
    // Priority 1: Authorization header with Bearer token
    const authHeader = req.headers['authorization'];
    if (authHeader && authHeader.startsWith('Bearer ')) {
      const token = authHeader.substring(7);
      console.log(`🔍 Found Bearer token: ${token.substring(0, 10)}...`);
      console.log(`🔍 Bearer token type: ${token.startsWith('sk-ant-') ? 'Anthropic API Token' : token.startsWith('oauth-') ? 'OAuth Token' : 'Custom User Token'}`);
      return token;
    }

    // Priority 2: x-api-key header (for compatibility)
    if (req.headers['x-api-key']) {
      const token = req.headers['x-api-key'];
      console.log(`🔍 Found x-api-key token: ${token.substring(0, 10)}...`);
      console.log(`🔍 x-api-key token type: ${token.startsWith('sk-ant-') ? 'Anthropic API Token' : token.startsWith('oauth-') ? 'OAuth Token' : 'Custom User Token'}`);
      return token;
    }

    // Priority 3: x-user-token header
    if (req.headers['x-user-token']) {
      const token = req.headers['x-user-token'];
      console.log(`🔍 Found x-user-token: ${token.substring(0, 10)}...`);
      return token;
    }

    // Priority 4: Query parameter (for testing)
    if (req.query && req.query.token) {
      const token = req.query.token;
      console.log(`🔍 Found query token: ${token.substring(0, 10)}...`);
      return token;
    }

    console.log(`❌ No token found in request`);
    return null;
  }

  /**
   * Middleware for user authentication
   * @returns {Function} Express middleware
   */
  middleware() {
    return (req, res, next) => {
      // Skip authentication if not enabled
      if (!this.enabled) {
        return next();
      }

      // Skip authentication for monitoring and health endpoints
      const publicPaths = ['/health', '/monitor', '/tokens', '/status', '/'];
      const publicPrefixes = ['/api/monitor/', '/api/users/'];
      
      if (publicPaths.includes(req.path) || 
          publicPrefixes.some(prefix => req.path.startsWith(prefix))) {
        return next();
      }

      // Skip authentication if this is an already-authenticated OAuth request
      // (indicated by an existing authenticatedUser property)
      if (req.authenticatedUser) {
        console.log(`🔄 Request already authenticated for user: ${req.authenticatedUser.name}, skipping re-authentication`);
        return next();
      }

      // Extract token from request
      const token = this.extractToken(req);

      if (!token) {
        return res.status(401).json({
          error: 'Authentication required',
          message: 'Please provide a valid user token'
        });
      }

      // Reject OAuth tokens and Anthropic API keys - they should not be used for user authentication
      if (token.startsWith('sk-ant-')) {
        console.log(`❌ Rejected Anthropic/OAuth token in user authentication: ${token.substring(0, 20)}...`);
        return res.status(403).json({
          error: 'Invalid authentication method',
          message: 'Please use a valid user token from .userlist, not an Anthropic API key or OAuth token'
        });
      }

      // Validate token
      const user = this.validateToken(token);

      if (!user) {
        return res.status(403).json({
          error: 'Proxy token error',
          message: 'Invalid user token'
        });
      }

      // Attach user to request for later use
      req.authenticatedUser = user;
      console.log(`🔐 Authenticated user: ${user.name} for ${req.method} ${req.path}`);
      
      next();
    };
  }

  /**
   * Get all users (for admin panel)
   */
  getAllUsers() {
    return this.users.map(user => ({
      name: user.name,
      // Don't expose the actual token
      hasToken: !!user.token
    }));
  }

  /**
   * Get authentication status
   */
  getStatus() {
    return {
      enabled: this.enabled,
      userCount: this.users.length,
      users: this.getAllUsers()
    };
  }

  /**
   * Add a new user
   * @param {string} name - User name
   * @param {string} token - User token
   * @returns {Object} The added user
   */
  addUser(name, token) {
    if (!name || !token) {
      throw new Error('Name and token are required');
    }

    // Check for duplicate token
    if (this.users.some(u => u.token === token)) {
      throw new Error('Token already exists');
    }

    const newUser = { name, token };
    this.users.push(newUser);
    this.saveUsers();
    this.enabled = true;
    console.log(`✅ Added new user: ${name}`);
    return newUser;
  }

  /**
   * Update an existing user
   * @param {number} index - User index
   * @param {string} name - New user name
   * @param {string} token - New user token
   * @returns {Object} The updated user
   */
  updateUser(index, name, token) {
    if (index < 0 || index >= this.users.length) {
      throw new Error('Invalid user index');
    }

    if (!name || !token) {
      throw new Error('Name and token are required');
    }

    // Check for duplicate token (excluding current user)
    if (this.users.some((u, i) => i !== index && u.token === token)) {
      throw new Error('Token already exists');
    }

    this.users[index] = { name, token };
    this.saveUsers();
    console.log(`✅ Updated user at index ${index}: ${name}`);
    return this.users[index];
  }

  /**
   * Delete a user
   * @param {number} index - User index
   * @returns {boolean} Success status
   */
  deleteUser(index) {
    if (index < 0 || index >= this.users.length) {
      throw new Error('Invalid user index');
    }

    const deletedUser = this.users[index];
    this.users.splice(index, 1);
    this.saveUsers();
    
    // Disable authentication if no users left
    if (this.users.length === 0) {
      this.enabled = false;
      console.log('⚠️  No users left, authentication disabled');
    }
    
    console.log(`✅ Deleted user: ${deletedUser.name}`);
    return true;
  }

  /**
   * Get all users with full information (for admin)
   * @returns {Array} All users
   */
  getAllUsersAdmin() {
    return [...this.users];
  }

  /**
   * Save users to file
   */
  saveUsers() {
    try {
      // Check if file exists, create it if it doesn't
      if (!fs.existsSync(this.userListPath)) {
        console.log('📝 Creating new .userlist file...');
      }
      
      fs.writeFileSync(this.userListPath, JSON.stringify(this.users, null, 2), 'utf8');
      console.log(`💾 Saved ${this.users.length} users to ${this.userListPath}`);
      
      // If this is the first user, enable authentication
      if (this.users.length > 0 && !this.enabled) {
        this.enabled = true;
        console.log('✅ User authentication enabled');
      }
    } catch (error) {
      console.error('❌ Error saving users:', error.message);
      throw new Error('Failed to save users');
    }
  }
}

// Export singleton instance
export const userAuthManager = new UserAuthManager();